package com.authenticateCenter.service.authority;

import cn.hutool.core.collection.CollectionUtil;
import com.authenticateCenter.assembler.UserAssembler;
import com.authenticateCenter.domain.entity.Authority;
import com.authenticateCenter.domain.entity.Role;
import com.authenticateCenter.domain.entity.RoleAuthority;
import com.authenticateCenter.domain.entity.User;
import com.authenticateCenter.domain.vo.UserVo;
import com.authenticateCenter.mapper.DomainEventMapper;
import com.authenticateCenter.mapper.UserMapper;
import com.authenticateCenter.service.IAuthorityService;
import com.authenticateCenter.service.IRoleAuthorityService;
import com.authenticateCenter.service.IRoleService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.common.jwtAutoConfiguration.Jwt;
import com.security.domain.authority.CommonRole;
import com.security.domain.authority.CommonUserDetails;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.ObjectUtils;

import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
import static com.authenticateCenter.factory.RoleFactory.ROLE_CONVERT;
import static com.authenticateCenter.factory.UserFactory.USER_CONVERT;

/**
 * @author 大忽悠
 * @create 2022/9/24 20:06
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class UserAuthorizeService {
    private final Jwt jwt;
    private final UserAssembler userAssembler;
    private final UserMapper userMapper;
    private final AntPathMatcher antPathMatcher=new AntPathMatcher();


    public String generatorToken(Integer id, String name) {
        if(!User.existCheckWithoutEx(name,userMapper)){

            return null;
        };
        return doGeneratorToken(id, name);
    }

    private String doGeneratorToken(Integer id, String name) {
        HashMap<String, Object> claims = new HashMap<>();
        claims.put("id", id);
        claims.put("sub", name);
        claims.put("created", new Date());
        log.info("为当前用户生成token中--> id: {} , authority: {}", id, name);
        return jwt.generateToken(claims);
    }

    public UserDetails verifyToken(String token, HttpServletResponse response) {
        String username = jwt.validateToken(token);
        if(username==null){
            return null;
        }
        UserDetails userDetails=getUserDetails(username);
        if (!refreshToken(token,response)) {
            return null;
        }
        return userDetails;
    }

    private Boolean refreshToken(String token, HttpServletResponse response) {
        String refreshToken = jwt.refreshToken(token);
        if(refreshToken==null){
            return false;
        }
        response.setHeader(jwt.getRefreshTokenOfResponseHeaderName(),refreshToken);
        return true;
    }

    private CommonUserDetails getUserDetails(String username) {
        UserVo userVo = userAssembler.assembler(new QueryWrapper<User>().eq("username", username));
        return userVo==null?null:USER_CONVERT.toUserDetails(userVo);
    }

    /**
     * @return 返回访问当前资源需要具备的角色权限,不考虑资源和角色被禁用的情况
     */
    public List<CommonRole> getRolesOfRequestUrl(String requestUrl, IAuthorityService iAuthorityService, IRoleService iRoleService, IRoleAuthorityService iRoleAuthorityService) {
        List<Authority> allAuthority = iAuthorityService.list();
        //当前资源访问不需要任何权限
        if(CollectionUtil.isEmpty(allAuthority)){
            return null;
        }
        //挨个资源进行匹配,找到符合当前请求的资源
        List<Integer> matchedAuthorityIdList = getMatchedAuthorityIdList(requestUrl, allAuthority);
        //当前资源访问不需要任何权限
        if(ObjectUtils.isEmpty(matchedAuthorityIdList)){
            return null;
        }
        //返回访问当前资源需要具备的角色集合
        List<Integer> matchedRoleIdList = iRoleAuthorityService.list(new QueryWrapper<RoleAuthority>().in("aid", matchedAuthorityIdList))
                .stream().map(RoleAuthority::getRid).distinct().collect(Collectors.toList());
        //访问当前资源不需要具备任何角色权限
        if(ObjectUtils.isEmpty(matchedRoleIdList)){
            return null;
        }
        return iRoleService.list(new QueryWrapper<Role>().in("id",matchedRoleIdList))
                .stream().map(role->ROLE_CONVERT.toCommonRole(role)).collect(Collectors.toList());
    }

    private List<Integer> getMatchedAuthorityIdList(String requestUrl, List<Authority> allAuthority) {
        List<Authority> matchPatterns=new ArrayList<>();
        allAuthority.forEach(authority -> {
            if(antPathMatcher.match(authority.getPattern(), requestUrl)){
                matchPatterns.add(authority);
            }
        });
        return matchPatterns.stream().map(Authority::getId).collect(Collectors.toList());
    }

    public CommonUserDetails getUserDetailsByUsername(String username) {
             return getUserDetails(username);
    }
}
